import time
import threading
import datetime
import numpy as np
import MetaTrader5 as mt5
from control.order_control import Order, OrderType
from worker.base.base_worker import BaseWorker
from utils.log_util import prints, saveLog
from constant.globl_constant import callbackTag
import constant.param_config as config


class BackWorker(BaseWorker):
    """
    关键点位回调下单
    """

    priceOffset = 8  # 价格差
    scopeScore = 30  # 回调幅度（百分比）
    nightEndTime = 2  # 晚上交易停止时间
    dayStartTime = 8  # 白天交易开始时间
    lastLevelPrice = 0
    timeLog = False
    alreadyLog = False
    sellMap = {}
    buyMap = {}

    def __init__(self):
        super().__init__()

    def startThread(self):
        """
        开启交易线程
        """
        thread = threading.Thread(target=self.worker)
        thread.start()

    def worker(self):

        prints("回调检测服务已启动...")

        while True:
            if self.isLogin and self.marketClose() is False:
                timeNow = datetime.datetime.now().hour
                if timeNow < self.nightEndTime or timeNow > self.dayStartTime:

                    if config.getBackOrderStatus() is False:
                        time.sleep(10)
                        continue

                    # 下单前检查，是否达到日内目标盈利和是否有重要事件发布
                    if self.createOrderCheck(self.alreadyLog,
                                             "回调下单服务") is False:
                        self.alreadyLog = True
                        time.sleep(10)
                        continue
                    self.alreadyLog = False

                    self.timeLog = False
                    self.priceLevel()
                elif self.timeLog is False:
                    saveLog("非交易时间，回调下单策略已停止检测")
                    self.timeLog = True
            time.sleep(10)

    def priceLevel(self):
        """
        阻力支撑位
        trend:  1:buy  2:sell
        level:  下标
        """

        allOrder = self.getPositionsDetail(symbol=self.symble)
        if len(allOrder) != 0:
            # 存在订单，禁止下单
            return

        price, trend, level = self.importantLevel()

        # 当前价格处于阻力位时清空之前支撑位，处于支撑位时清空之前阻力位
        if trend != None and level != None and price != None:
            if trend == 1 and (level not in self.buyMap or
                               (level in self.buyMap
                                and self.buyMap[level] != price)):
                self.buyMap[level] = price
                self.sellMap = {}
                saveLog("支撑位更新：" + str(self.buyMap))
            elif trend == 2 and (level not in self.sellMap or
                                 (level in self.sellMap
                                  and self.sellMap[level] != price)):
                self.sellMap[level] = price
                self.buyMap = {}
                saveLog("阻力位更新：" + str(self.sellMap))

        currentPrice = self.control.getCurrentPrice(symbol=self.symble)
        lastClosePrice = self.getClosePriceArray(self.symble, 15)[-2]
        highPrice, lowPrice, openPrice, closePrice = self.dayPriceInfo(
            self.symble)

        if len(self.sellMap) != 0:
            maxSellPrice = max(self.sellMap.values())
            # 价格处于阻力位时，日内最低价与到达的最大阻力位之间的距离大于限定值时，并且当前价格在阻力位之下
            if currentPrice < maxSellPrice - self.goldPriceOffset:
                if maxSellPrice - lowPrice > self.priceOffset:
                    # 回调幅度占日内跌幅的百分比，（最大阻力位-当前价格）/（最大阻力位-日内最低价）

                    downScope = int(((maxSellPrice - currentPrice) /
                                     (maxSellPrice - lowPrice) * 10000) / 100)
                    if downScope > self.scopeScore and currentPrice < lastClosePrice:
                        if self.maSlope() == 2:
                            self.sendOrder(OrderType.SELL, currentPrice)
        elif len(self.buyMap) != 0:
            minBuyPrice = min(self.buyMap.values())
            # 价格处于支撑位时，日内最高价与到达的最小支撑位之间的距离大于限定值时，并且当前价格在支撑位之上
            if currentPrice > minBuyPrice + self.goldPriceOffset:
                if highPrice - minBuyPrice > self.priceOffset:
                    # 回调幅度占日内跌幅的百分比，（当前价格-最小支撑位）/（日内最高价-最小支撑位）

                    upScope = int(((currentPrice - minBuyPrice) /
                                   abs(minBuyPrice - highPrice) * 10000) / 100)

                    if upScope > self.scopeScore and currentPrice > lastClosePrice:
                        if self.maSlope() == 1:
                            self.sendOrder(OrderType.BUY, currentPrice)

    def maSlope(self):
        """
        1分钟周期200日均线斜率
        return 1:涨   2:跌
        """

        m1ClosePrice = self.getClosePriceArray(self.symble,
                                               mt5.TIMEFRAME_M1,
                                               count=400)
        m1SMA = self.indicator.maValueForTimeArray(closeArr=m1ClosePrice,
                                                   timeArray=[200],
                                                   size=400)
        value = np.gradient(m1SMA[0])[-5:]
        buySize = [item for item in value if item > 0]
        sellSize = [item for item in value if item < 0]
        if len(buySize) == len(value):
            return 1
        elif len(sellSize) == len(value):
            return 2
        return 0

    def sendOrder(self, t, currentPrice):
        tp = 0
        sp = 0
        orderType = None

        if t == OrderType.BUY:
            saveLog("回调幅度满足要求，创建多单")
            orderType = Order.CREATE_BUY
            tp = self.getStrategyTp(Order.CREATE_BUY)
            sp = currentPrice - 2
        else:
            saveLog("回调幅度满足要求，创建空单")
            orderType = Order.CREATE_SELL
            tp = self.getStrategyTp(Order.CREATE_SELL)
            sp = currentPrice + 2

        price = self.control.getCurrentPrice(self.symble)

        # 是否超过上一单平仓价
        if self.surpassPrice(orderType, price) is False:
            self.control.createOrder(t,
                                     self.symble,
                                     priceTp=tp,
                                     priceSp=sp,
                                     remark=callbackTag)
        else:
            saveLog("当前价格未超过上一单平仓价，禁止回调下单")
